#include "MelodyCandidate.h"
#include "RandomNumberGenerator.h"
#include "QDebug"

MelodyCandidate::MelodyCandidate()
{
}

MelodyCandidate::MelodyCandidate(int genomeSize, float fitness)
    : Candidate(genomeSize,fitness)
{
}

void MelodyCandidate::swapSubString(Candidate* mate,int crossoverIndex) {
    std::vector<float> tempGenome = getGenome();
    std::vector<float> tempMate = mate->getGenome();
    int cIndex;
    //qDebug() << "Init genome size: " << this->genome.size();
    //qDebug() << "Init mate size: " << mate->getGenome().size();
    if(getGenome().size()<mate->getGenome().size()) {
        cIndex = (RandomNumberGenerator::nextInt((getGenome().size()/6)-3) * 6) +12;
    } else {
        cIndex = (RandomNumberGenerator::nextInt((mate->getGenome().size()/6)-3) * 6) +12;
    }
    //Clear Top Half of each Genome
    //qDebug() << "cIndex: " << cIndex;
    ((MelodyCandidate*)mate)->truncateGenome(cIndex);
    //qDebug() << "Truncated mate size: " << mate->getGenome().size();
    truncateGenome(cIndex);
    //qDebug() << "Truncated genome size: " << this->genome.size();

    //qDebug() << "Tempmate size: " << tempMate.size();
    //Copy top half of mate to this Genome
    for(int i=cIndex;i<tempMate.size();i++) {
        this->genome.push_back(tempMate.at(i));
    }
    //qDebug() << "Resultant genome size: " << this->genome.size();
    //Copy top half of this genome to mate
    for(int i=cIndex;i<tempGenome.size();i++) {
        mate->addChromosome(tempGenome.at(i));
    }
    //qDebug() << "Resultant mate size: " << mate->getGenome().size();
}
void MelodyCandidate::truncateGenome(int cIndex) {
    this->genome.erase(this->genome.begin()+cIndex,this->genome.end());
}

void MelodyCandidate::mutate(float mutationRate, float mutationAmount) {
    if((RandomNumberGenerator::nextFloat(1) < mutationRate) || (mutationRate==1)) {
        int index = 0;
        for(int i=0;i<(int)genome.size()*(mutationAmount);i++) {
            index = RandomNumberGenerator::nextInt(genome.size());
            if(index%6==0) {
                genome.at(index) = RandomNumberGenerator::nextInt(8);
            } else if(index%6==1) {
                genome.at(index) = RandomNumberGenerator::nextInt(50)+40;
            } else {
                genome.at(index) = RandomNumberGenerator::nextInt(999);
            }
        }
        this->extremalOptimization(RandomNumberGenerator::nextInt(this->genome.size()-1)/6);
        /*
        int modLength = RandomNumberGenerator::nextInt(5) -2;
        if(modLength>0) {
            for(int i=0;i<modLength;i++) {
                genome.push_back(RandomNumberGenerator::nextInt(6));
                genome.push_back(RandomNumberGenerator::nextInt(50)+30);
                genome.push_back(RandomNumberGenerator::nextInt(999));
                genome.push_back(RandomNumberGenerator::nextInt(999));
                genome.push_back(RandomNumberGenerator::nextInt(999));
                genome.push_back(RandomNumberGenerator::nextInt(999));
            }
        } else if(modLength< 0){
            if(genome.size()>3) {
                for(int i=0;i<(modLength*-1);i++) {
                    genome.erase(genome.end() -6,genome.end());
                }
            }
        }
        */
    }
}

void MelodyCandidate::extremalOptimization(int chromosome) {
    std::vector<float> tempNote;
    int transpose =  RandomNumberGenerator::nextInt(24) - 12;
    for(int i=0;i<6;i++) {
        if(i==1) {
            tempNote.push_back(
                    (((int)this->genome.at(((chromosome*6)+i))) + transpose)%127
            );
        } else  {
            tempNote.push_back(this->genome.at((chromosome*6)+i));
        }
    }
    this->genome.erase(this->genome.begin()+(chromosome*6),this->genome.begin()+((chromosome*6)+6));
    int index = RandomNumberGenerator::nextInt(this->genome.size()/6);
    this->genome.insert(this->genome.begin()+(index*6),tempNote.begin(),tempNote.end());
}
void MelodyCandidate::variation() {
    int index = RandomNumberGenerator::nextInt(genome.size());
    if(index%6==0) {
        genome.at(index) = RandomNumberGenerator::nextInt(8);
    } else if(index%6==1) {
        genome.at(index) = RandomNumberGenerator::nextInt(50)+40;
    } else {
        genome.at(index) = RandomNumberGenerator::nextInt(999);
    }
    if(RandomNumberGenerator::nextFloat(1) < 0.25) {
        this->extremalOptimization(RandomNumberGenerator::nextInt(this->genome.size()-1)/6);
    }
}
